Passed
Push — master ( 3a5b1d...3cfbdf )
by June
01:07
created

PokemonDB.indexSecondaryPrefix   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 3
nop 4
dl 0
loc 7
rs 10
1
/****
2
 * This module creates an in-memory Pokemon Database for Generation 1 Games
3
 * It uses a very small memory footprint and speedy-quick navigation
4
 * This happens through circular references which come with a lot of pitfalls
5
 *      * Make sure to only keep a single instance of this in memory, Javascript
6
 *        has a lot of issues with garbage collecting circular references.
7
 *      * If deep navigating the database, be very careful about not ending up
8
 *        in infinite loops.
9
 *      * You cannot use JSON.stringify or certain other tools, at least not
10
 *        without some careful prep work beforehand
11
 *
12
 * This was created initially for the Pokered Save Editor which works just fine
13
 * with the pitfalls of circular references but for other uses caution may need
14
 * to be taken.
15
 */
16
17
// Import Dependencies
18
const _ = require("lodash");
19
20
// Import Raw JSON Files
21
const itemsRaw = require("./data/items.json");
22
const movesRaw = require("./data/moves.json");
23
const pokemonRaw = require("./data/pokemon.json");
24
const typesRaw = require("./data/types.json");
25
26
const PokemonDB = exports.PokemonDB = function() {
27
    this.items = [];
28
    this.moves = [];
29
    this.pokemon = [];
30
    this.types = [];
31
32
    this.rebuild();
33
}
34
35
PokemonDB.prototype.rebuild = function() {
36
    // Setup primary index
37
    this.indexPrimary(this.itemsRaw, this.items, "ind");
38
    this.indexPrimary(this.movesRaw, this.moves, "ind");
39
    this.indexPrimary(this.pokemonRaw, this.pokemon, "ind");
40
    this.indexPrimary(this.typesRaw, this.types, "ind");
41
42
    // Add in aliases for names as-is
43
    this.indexSecondary(this.itemsRaw, this.items, "name", "ind");
44
    this.indexSecondary(this.movesRaw, this.moves, "name", "ind");
45
    this.indexSecondary(this.pokemonRaw, this.pokemon, "name", "ind");
46
    this.indexSecondary(this.typesRaw, this.types, "name", "ind");
47
48
    // Add in aliases for names in snake_case form
49
    this.indexSecondarySnake(this.itemsRaw, this.items, "name", "ind");
50
    this.indexSecondarySnake(this.movesRaw, this.moves, "name", "ind");
51
    this.indexSecondarySnake(this.pokemonRaw, this.pokemon, "name", "ind");
52
    this.indexSecondarySnake(this.typesRaw, this.types, "name", "ind");
53
54
    // Add in aliases prefixed
55
    this.indexSecondaryPrefix(this.itemsRaw, this.items, "tm", "ind");
56
    this.indexSecondaryPrefix(this.itemsRaw, this.items, "hm", "ind");
57
58
    this.indexSecondaryPrefix(this.movesRaw, this.moves, "tm", "ind");
59
    this.indexSecondaryPrefix(this.movesRaw, this.moves, "hm", "ind");
60
61
    this.indexSecondaryPrefix(this.pokemonRaw, this.pokemon, "pokedex", "ind");
62
63
    // Circular Link everything
64
    // Yes I'm aware of the dangers and pitfalls of circular linking
65
    // I'm choosing it anyways
66
    this.process2Items();
67
    this.process2Moves();
68
    this.process2Pokemon();
69
}
70
71
// Indexes all items by deep cloning each item and adding it to the object under key value
72
PokemonDB.prototype.indexPrimary = function(from, to, key) {
73
    for(let i = 0; i < from.length; i++) {
74
        const entry = from[i];
75
        to[entry[key]] = _.cloneDeep(entry);
76
    }
77
}
78
79
// Creates a 2nd index which just aliases the first index
80
PokemonDB.prototype.indexSecondary = function(from, to, key, origKey) {
81
    for(let i = 0; i < from.length; i++) {
82
        const entry = from[i];
83
        to[entry[key]] = to[entry[origKey]];
84
    }
85
}
86
87
// Creates a 2nd index snake_case'd which just aliases the first index
88
PokemonDB.prototype.indexSecondarySnake = function(from, to, key, origKey) {
89
    for(let i = 0; i < from.length; i++) {
90
        const entry = from[i];
91
        to[_.snakeCase(entry[key])] = to[entry[origKey]];
92
    }
93
}
94
95
// Creates a 2nd index prefixed which just aliases the first index
96
// Only creates alias if key exists
97
PokemonDB.prototype.indexSecondaryPrefix = function(from, to, key, origKey) {
98
    for(let i = 0; i < from.length; i++) {
99
        const entry = from[i];
100
        if(entry[key] !== undefined)
101
            to['' + key + entry[key]] = to[entry[origKey]];
1 ignored issue
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
102
    }
103
}
104
105
PokemonDB.prototype.process2Items = function() {
106
    const self = this;
107
108
    _.each(self.items, function(value) {
109
        if(value == undefined)
0 ignored issues
show
Best Practice introduced by
Comparing value to undefined using the == operator is not safe. Consider using === instead.
Loading history...
110
            return;
1 ignored issue
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
111
112
        if(value.tm !== undefined && value._tm === undefined) {
113
            value._tm = value.tm;
114
            value.tm = _.find(self.moves, ['tm', value.tm]);
115
        }
116
        if(value.hm !== undefined && value._hm === undefined) {
117
            value._hm = value.hm;
118
            value.hm = _.find(self.moves, ['hm', value.hm]);
119
        }
120
    });
121
}
122
123
PokemonDB.prototype.process2Moves = function() {
124
    const self = this;
125
126
    _.each(self.moves, function(value) {
127
        if(value == undefined)
0 ignored issues
show
Best Practice introduced by
Comparing value to undefined using the == operator is not safe. Consider using === instead.
Loading history...
128
            return;
1 ignored issue
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
129
        
130
        if(value.type !== undefined && value._type === undefined) {
131
            value._type = value.type;
132
            value.type = _.find(self.types, ['name', value.type]);
133
        }
134
        if(value.tm !== undefined && value._tm === undefined) {
135
            value._tm = value.tm;
136
            value.tm = _.find(self.items, ['_tm', value.tm]);
137
        }
138
        if(value.hm !== undefined && value._hm === undefined) {
139
            value._hm = value.hm;
140
            value.hm = _.find(self.items, ['_hm', value.hm]);
141
        }
142
    });
143
}
144
145
PokemonDB.prototype.process2Pokemon = function() {
146
    const self = this;
147
148
    _.each(self.pokemon, function(value) {
149
        if(value == undefined)
0 ignored issues
show
Best Practice introduced by
Comparing value to undefined using the == operator is not safe. Consider using === instead.
Loading history...
150
            return;
1 ignored issue
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
151
152
        if(value.moves !== undefined) {
153
            for(let i = 0; i < value.moves.length; i++) {
154
                const move = value.moves[i];
155
                if(move._move !== undefined)
156
                    continue;
1 ignored issue
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
157
158
                move._move = move.move;
159
                move.move = _.find(self.moves, ['name',move.move]);
160
            }
161
        }
162
163
        self._processMoveList(value, "initial", "name", self);
164
        self._processMoveList(value, "tmHm", "_tm", self);
165
166
        if(value.type1 !== undefined && value._type1 === undefined) {
167
            value._type1 = value.type1;
168
            value.type1 = _.find(self.types, ['name', value.type1]);
169
        }
170
171
        if(value.type2 !== undefined && value._type2 === undefined) {
172
            value._type2 = value.type2;
173
            value.type2 = _.find(self.types, ['name', value.type2]);
174
        }
175
176
        if(value.evolution !== undefined) {
177
            if(Array.isArray(value.evolution)) {
178
                for(let i = 0; i < value.evolution.length; i++) {
179
                    self._processEvolutionEntry(value.evolution[i], value, self);
180
                }
181
            }
182
            else
183
                self._processEvolutionEntry(value.evolution, value, self);
1 ignored issue
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
184
        }
185
    });
186
}
187
188
PokemonDB.prototype._processMoveList = function(value, from, key, self) {
189
    if(value[from] !== undefined && value['_' + from] === undefined) {
190
        value['_' + from] = _.cloneDeep(value[from]);
191
        for(let i = 0; i < value[from].length; i++) {
192
            const val = value[from][i];
193
            value[from][i] = _.find(self.moves, [key, val]);
194
        }
195
    }
196
}
197
198
PokemonDB.prototype._processEvolutionEntry = function(entry, value, self) {
199
    if(entry.item !== undefined && entry._item === undefined) {
200
        entry._item = entry.item;
201
        entry.item = _.find(self.items, ['name', entry.item]);
202
    }
203
204
    if(entry._toName !== undefined)
205
        return;
1 ignored issue
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
206
207
    entry._toName = entry.toName;
208
    entry.toName = _.find(self.pokemon, ['name', entry.toName]);
209
210
    entry.toName.deEvolution = value;
211
}
212
213
// Add several ways to access the raw data, nothings duplicated because it's just all copying
214
// by reference
215
PokemonDB.itemsRaw = PokemonDB.prototype.itemsRaw = itemsRaw;
216
PokemonDB.movesRaw = PokemonDB.prototype.movesRaw = movesRaw;
217
PokemonDB.typesRaw = PokemonDB.prototype.typesRaw = typesRaw;
218
PokemonDB.pokemonRaw = PokemonDB.prototype.pokemonRaw = pokemonRaw;
219